Add validate input --server flag for persistent HTTP/REST#3386
Add validate input --server flag for persistent HTTP/REST#3386simonbaird wants to merge 12 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds persistent HTTP server mode for ChangesValidate Input Server Mode
Estimated code review effort: 4 (Complex) | ~60 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
f38bff3 to
f00abb9
Compare
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
docs/modules/ROOT/pages/ec_validate_input.adoc (1)
12-22: 🔒 Security & Privacy | 🔵 TrivialConsider documenting network exposure/security guidance for server mode.
The server binds on all interfaces (
:<port>) with no authentication (perinternal/server/server.go). Given this is now a persistent network-facing service, docs could note that it should be run behind a firewall/reverse proxy or restricted to trusted networks.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/modules/ROOT/pages/ec_validate_input.adoc` around lines 12 - 22, Update the server-mode documentation in ec_validate_input.adoc to add a brief security note that the persistent HTTP server started by --server binds on all interfaces and has no authentication. Mention that users should run it behind a firewall or reverse proxy, or restrict it to trusted networks, and place this guidance near the existing endpoint/server-mode description so it is easy to find.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cmd/validate/input.go`:
- Around line 146-159: The `--workers` option is currently ignored when
`data.serverMode` is true because `server.New(server.Config{...})` does not use
`Config.Workers`. Update the server path by either plumbing `data.workers`
through `internal/server` and consuming it in the relevant server code, or
remove/hide the flag from server mode so `cmd/validate/input.go` and
`server.Config` do not expose a misleading no-op setting.
- Around line 146-162: Pass a signal-aware context from the root command so
server shutdown can observe cancellation on SIGINT/SIGTERM. Update the root
execution path in cmd/root.go to use a context tied to OS signals instead of
context.Background(), and ensure validate/input.go’s server.New/srv.Start path
continues to consume cmd.Context() so srv.Start can react to ctx.Done() and exit
gracefully.
In `@internal/server/handler.go`:
- Around line 81-84: The evaluation and report build failure paths in handler
logic are leaking raw internal error text to API clients. Keep the detailed
error in server-side logging via the existing log.WithField("error", err) calls
in the handler flow, but change the client-facing responses in the evaluation
and report-build branches to return a generic message instead of fmt.Sprintf
with %v. Update the relevant error handling in the handler method that writes
responses so both failure cases use safe, non-internal text.
- Around line 149-159: The isValidInput helper currently skips validation for
explicit YAML content types, so malformed YAML can slip through and fail later
as a server error. Update isValidInput to validate application/yaml,
application/x-yaml, and text/yaml with utils.IsYamlMap instead of returning
true, and keep the existing JSON parsing behavior for application/json and the
default fallback. Since inputExtension uses the same content-type switch,
consider centralizing the YAML/JSON content-type handling there to avoid
divergence between the two helpers.
- Around line 78-87: Add a timeout around the evaluation flow in
handleValidateInput, since the request context is passed directly into each
evaluator and a slow run can hang the handler. Create a derived context with
context.WithTimeout before the loop that calls e.Evaluate, use that context for
every evaluator invocation, and cancel it when finished. Keep the existing error
handling and logging in the evaluator loop unchanged, but ensure the new
deadline applies to the entire evaluation sequence.
In `@internal/server/server.go`:
- Around line 35-43: The Config.Workers field is currently unused, so request
validation still runs with unbounded concurrency. Update Server to use Workers
as a concurrency limit by adding a semaphore (or equivalent limiter) in the
request path, wiring it through New/Start and enforcing it inside
handleValidateInput before policy evaluation begins. If you do not intend to
bound concurrency, remove Workers from Config and any related setup so the API
stays consistent.
- Around line 83-87: `httpServer` in the server startup setup only sets
`ReadHeaderTimeout`, so add explicit `ReadTimeout`, `WriteTimeout`, and
`IdleTimeout` on the `http.Server` configuration to bound slow client
connections. Update the `http.Server` initialization in the code path that
builds the listener for `handler`, keeping the existing `Addr` and
`ReadHeaderTimeout` values, and choose sensible timeout values consistent with
the service’s expected request/response behavior.
---
Nitpick comments:
In `@docs/modules/ROOT/pages/ec_validate_input.adoc`:
- Around line 12-22: Update the server-mode documentation in
ec_validate_input.adoc to add a brief security note that the persistent HTTP
server started by --server binds on all interfaces and has no authentication.
Mention that users should run it behind a firewall or reverse proxy, or restrict
it to trusted networks, and place this guidance near the existing
endpoint/server-mode description so it is easy to find.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 1c1eb87d-d23f-4ada-87fa-e76939c91a9a
⛔ Files ignored due to path filters (1)
features/__snapshots__/validate_input_server.snapis excluded by!**/*.snap
📒 Files selected for processing (9)
acceptance/acceptance_test.goacceptance/cli/server.gocmd/validate/input.godocs/modules/ROOT/pages/ec_validate_input.adocfeatures/validate_input_server.featureinternal/server/handler.gointernal/server/middleware.gointernal/server/server.gointernal/server/server_test.go
|
🤖 Finished Review · ✅ Success · Started 11:15 AM UTC · Completed 11:21 AM UTC |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cmd/validate/input_test.go (1)
312-325: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFixed sleep risks flakiness and the assertion is too weak to validate graceful shutdown.
The 100ms sleep before
cancel()is a fixed race window; under CI load, PreRunE/server startup may not have progressed enough, making the test pass without actually exercising the server path. Also, whenerr == nilthe test asserts nothing — it can't confirm the server actually started and then shut down cleanly on context cancellation (which is also the scenario flagged incmd/root.goaround theExecute()fatal-error path). Consider synchronizing on an actual readiness signal instead of a sleep, and assertingrequire.NoError(t, err)for the graceful-shutdown case once ctx-cancellation is confirmed to return nil.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmd/validate/input_test.go` around lines 312 - 325, The test in validateCmd.Execute relies on a fixed time.Sleep before canceling, which makes the server-path check flaky and non-deterministic. Replace that timing-based pause with a real readiness/synchronization signal from the server startup path (for example in the PreRunE/server startup flow) so the test only cancels after the server is actually running. Then strengthen the assertion in the graceful-shutdown case by requiring a nil error after context cancellation, and keep the existing flag-validation negative checks only for the error path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cmd/validate/input_test.go`:
- Around line 312-325: The test in validateCmd.Execute relies on a fixed
time.Sleep before canceling, which makes the server-path check flaky and
non-deterministic. Replace that timing-based pause with a real
readiness/synchronization signal from the server startup path (for example in
the PreRunE/server startup flow) so the test only cancels after the server is
actually running. Then strengthen the assertion in the graceful-shutdown case by
requiring a nil error after context cancellation, and keep the existing
flag-validation negative checks only for the error path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 44a54a24-52ab-41d0-9626-d0380a433d6d
📒 Files selected for processing (7)
acceptance/cli/server.gocmd/root.gocmd/validate/input.gocmd/validate/input_test.gointernal/server/handler.gointernal/server/server.gointernal/server/server_test.go
💤 Files with no reviewable changes (1)
- cmd/validate/input.go
🚧 Files skipped from review as they are similar to previous changes (4)
- acceptance/cli/server.go
- internal/server/handler.go
- internal/server/server_test.go
- internal/server/server.go
ReviewVerdict: Approve ✅ This PR adds a well-structured Strengths
Observations (non-blocking)
Labels: PR adds new --server flag and internal/server/ package for persistent HTTP mode Previous runReview — ApproveThis PR adds a persistent HTTP server mode to Strengths
Findings1. Concurrency contract on Evaluator — documented but not stress-tested (low) The new doc comment on 2. In 3. Flag help text says "Mutually exclusive with --file" (low) The 4. Unrelated Makefile change included (low) The lint/lint-fix targets switch from Architecture Notes
Labels: PR adds a new HTTP server mode to the CLI, touching CLI flags, internal server package, evaluator interface docs, and acceptance tests Previous run (2)Review —
|
|
Last change is adding explanatory comments to address the potential concerns. |
|
🤖 Finished Review · ✅ Success · Started 3:40 PM UTC · Completed 3:45 PM UTC |
|
I've addressed a few more agentic review suggestions and nitpicks. |
7f68917 to
5973317
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cmd/validate/input_test.go (1)
289-316: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueFixed 200ms timeout may be flaky in CI.
The test relies on completing policy loading, evaluator init, HTTP bind, and graceful shutdown all within a fixed 200ms window (Line 299). Under CI load this could intermittently fail before the server even finishes starting up, or pass without genuinely exercising a listening server. Consider a more generous timeout or asserting readiness (e.g., poll
/ready) before triggering shutdown.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cmd/validate/input_test.go` around lines 289 - 316, The server-mode test in Test_ValidateInputCmd is using a fixed 200ms context timeout that can race in CI; make the test wait for actual readiness instead of relying on a short deadline. Update the context setup and shutdown flow around validateCmd.Execute so it either uses a more generous timeout or polls the server’s readiness endpoint before canceling, ensuring the server has bound and started before the test ends.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@cmd/validate/input_test.go`:
- Around line 289-316: The server-mode test in Test_ValidateInputCmd is using a
fixed 200ms context timeout that can race in CI; make the test wait for actual
readiness instead of relying on a short deadline. Update the context setup and
shutdown flow around validateCmd.Execute so it either uses a more generous
timeout or polls the server’s readiness endpoint before canceling, ensuring the
server has bound and started before the test ends.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: ad73f828-e941-4b96-8e50-0b83c88e1c96
📒 Files selected for processing (6)
cmd/validate/input.gocmd/validate/input_test.godocs/modules/ROOT/pages/ec_validate_input.adocinternal/evaluator/conftest_evaluator.gointernal/evaluator/evaluator.gointernal/server/server.go
✅ Files skipped from review due to trivial changes (3)
- internal/evaluator/evaluator.go
- internal/evaluator/conftest_evaluator.go
- docs/modules/ROOT/pages/ec_validate_input.adoc
🚧 Files skipped from review as they are similar to previous changes (2)
- cmd/validate/input.go
- internal/server/server.go
|
Claude Opus 4.6's response to the remaining nitpick:
|
|
The e2e fail log includes this, so maybe a flake: |
|
/retest |
Fix a long-running annoyance. Avoid these kind of errors when running `make lint` locally: Missing license header in: input.yaml Missing license header in: zz.yaml (Unrelated to, but included in PR for...) Ref: https://redhat.atlassian.net/browse/EC-1882 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5973317 to
53dcde7
Compare
|
🤖 Review · ❌ Terminated · Started 4:42 PM UTC · Ended 4:49 PM UTC |
|
I rebased, fixed some conflicts, squashed the "add a comment to explain a decision" commits. |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
Makefile (2)
230-230: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
git ls-filesskips untracked files.Switching from scanning
.togit ls-files -zmeans brand-new files that haven't beengit added yet are silently skipped by both the license check andlint-fix. Likely fine for CI (files are committed by then) but can surprise local dev workflows.Also applies to: 238-238
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Makefile` at line 230, The license check and lint-fix steps now use git ls-files -z, which skips brand-new untracked files and can hide missing headers during local development. Update the Makefile targets that invoke addlicense and lint-fix so they still cover untracked files as well as tracked ones, using the existing license-check/lint-fix command blocks as the place to adjust the file discovery logic.
230-232: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueAvoid double-running addlicense just to recover the exit code.
Piping to
seddrops the exit status, soaddlicenseis invoked a second time solely to fail the build. This doubles cost for no functional gain;pipefail(if the recipe shell is bash) would let a single invocation preserve both output prefixing and exit status.♻️ Suggested consolidation (requires bash shell for the recipe)
+SHELL := /bin/bash + lint: tekton-lint go-mod-lint ## Run linter # addlicense doesn't give us a nice explanation so we prefix it with one - `@git` ls-files -z | xargs -0 go run -modfile tools/go.mod github.com/google/addlicense -c '$(COPY)' -y '' -s -check $(LICENSE_IGNORE) | sed 's/^/Missing license header in: /g' -# piping to sed above looses the exit code, luckily addlicense is fast so we invoke it for the second time to exit 1 in case of issues - `@git` ls-files -z | xargs -0 go run -modfile tools/go.mod github.com/google/addlicense -c '$(COPY)' -y '' -s -check $(LICENSE_IGNORE) >/dev/null 2>&1 + `@set` -o pipefail; git ls-files -z | xargs -0 go run -modfile tools/go.mod github.com/google/addlicense -c '$(COPY)' -y '' -s -check $(LICENSE_IGNORE) | sed 's/^/Missing license header in: /g'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Makefile` around lines 230 - 232, The Makefile license-check recipe in the addlicense target is running addlicense twice just to preserve the exit code after piping through sed. Consolidate this into a single invocation by using a shell that supports pipefail (for example, the recipe shell for this target) so the existing git ls-files | xargs -0 | addlicense | sed flow keeps the prefixed output and still returns the correct failure status. Update the addlicense command block and its surrounding shell setup so the target no longer repeats the check solely for exit-code recovery.internal/server/server_test.go (1)
293-346: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winFlaky test pattern: port reuse race + fixed sleep.
Binding a listener to get a free port then closing it before rebinding (Line 294-297) is a TOCTOU race — another process could grab the port in between, causing intermittent CI failures. Similarly, the fixed
time.Sleep(100ms)(Line 330) to wait for server startup is timing-dependent and can flake under load.Consider polling
/livewith retries/backoff instead of a fixed sleep, and consider usinghttptest.Server(which handles port allocation atomically) if the design doesn't strictly require exercisingListenAndServe/Shutdowndirectly.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/server/server_test.go` around lines 293 - 346, The TestServerLifecycle test is flaky because it reserves a port by opening and closing a listener before starting the HTTP server, and it uses a fixed sleep to wait for readiness. Update TestServerLifecycle to avoid the port reuse TOCTOU by using atomic test server setup such as httptest.Server when possible, or otherwise keep the listener open through server startup; then replace the hardcoded time.Sleep with polling the /live endpoint with retry/backoff until the server is ready. Keep the shutdown assertions around httpServer.ListenAndServe, httpServer.Shutdown, and the /live request flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@internal/server/server_test.go`:
- Around line 293-346: The TestServerLifecycle test is flaky because it reserves
a port by opening and closing a listener before starting the HTTP server, and it
uses a fixed sleep to wait for readiness. Update TestServerLifecycle to avoid
the port reuse TOCTOU by using atomic test server setup such as httptest.Server
when possible, or otherwise keep the listener open through server startup; then
replace the hardcoded time.Sleep with polling the /live endpoint with
retry/backoff until the server is ready. Keep the shutdown assertions around
httpServer.ListenAndServe, httpServer.Shutdown, and the /live request flow.
In `@Makefile`:
- Line 230: The license check and lint-fix steps now use git ls-files -z, which
skips brand-new untracked files and can hide missing headers during local
development. Update the Makefile targets that invoke addlicense and lint-fix so
they still cover untracked files as well as tracked ones, using the existing
license-check/lint-fix command blocks as the place to adjust the file discovery
logic.
- Around line 230-232: The Makefile license-check recipe in the addlicense
target is running addlicense twice just to preserve the exit code after piping
through sed. Consolidate this into a single invocation by using a shell that
supports pipefail (for example, the recipe shell for this target) so the
existing git ls-files | xargs -0 | addlicense | sed flow keeps the prefixed
output and still returns the correct failure status. Update the addlicense
command block and its surrounding shell setup so the target no longer repeats
the check solely for exit-code recovery.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: efe71d8a-f745-42a4-acb1-b4fc89c764a9
⛔ Files ignored due to path filters (1)
features/__snapshots__/validate_input_server.snapis excluded by!**/*.snap
📒 Files selected for processing (14)
Makefileacceptance/acceptance_test.goacceptance/cli/server.gocmd/root.gocmd/validate/input.gocmd/validate/input_test.godocs/modules/ROOT/pages/ec_validate_input.adocfeatures/validate_input_server.featureinternal/evaluator/conftest_evaluator.gointernal/evaluator/evaluator.gointernal/server/handler.gointernal/server/middleware.gointernal/server/server.gointernal/server/server_test.go
✅ Files skipped from review due to trivial changes (3)
- internal/evaluator/conftest_evaluator.go
- internal/evaluator/evaluator.go
- docs/modules/ROOT/pages/ec_validate_input.adoc
🚧 Files skipped from review as they are similar to previous changes (9)
- features/validate_input_server.feature
- acceptance/acceptance_test.go
- cmd/root.go
- internal/server/middleware.go
- cmd/validate/input_test.go
- acceptance/cli/server.go
- internal/server/server.go
- cmd/validate/input.go
- internal/server/handler.go
|
🤖 Finished Review · ✅ Success · Started 4:42 PM UTC · Completed 4:49 PM UTC |
Add --server and --server-port flags to `ec validate input` that start a persistent HTTP server instead of running a one-shot evaluation. Policies are loaded once at startup via pre-created evaluators. The server shuts down gracefully on context cancellation. Health endpoints /live and /ready support Kubernetes-style probes. Ref: https://redhat.atlassian.net/browse/EC-1883 Ref: https://redhat.atlassian.net/browse/EC-1886 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add POST /v1/validate/input endpoint that accepts JSON or YAML input, evaluates it against pre-loaded policies, and returns the same JSON report structure as `--output json`. Includes Content-Type detection, 10MB body size limit, structured JSON error responses, and panic recovery middleware. Ref: https://redhat.atlassian.net/browse/EC-1884 Ref: https://redhat.atlassian.net/browse/EC-1887 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add request logging middleware that logs method, path, status code, latency, and remote address for every request. Switch to JSON log format in server mode for log aggregation in containerized environments. Log server lifecycle events (startup config, policy loading, shutdown). Ref: https://redhat.atlassian.net/browse/EC-1908 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update CLI help text to describe server mode, available endpoints, request/response format, and configuration options. Add usage examples for starting the server and sending evaluation requests with curl. Ref: https://redhat.atlassian.net/browse/EC-1889 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test health endpoints (/live, /ready), evaluation endpoint (success, violations, errors, YAML input, empty body, invalid input), recovery middleware, and server lifecycle (start, request handling, shutdown). Uses mock evaluators and stub policy for isolation. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The way the http service is tested is to start, access, then stop the http service synchronously, rather than have a persistent http service running in a container. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The server was binding to all interfaces (0.0.0.0) by default, exposing the unauthenticated evaluation endpoint on any network interface. Default to 127.0.0.1 and let users opt in to network exposure with --server-address 0.0.0.0. (Change suggested during code review.) Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A slow evaluator could hang the handler indefinitely since the request context had no deadline. Wrap the evaluation loop in a 90-second timeout and add a test that verifies the handler returns an error when exceeded. (Change suggested during code review.) Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace http.Get/http.Post with http.NewRequestWithContext and http.DefaultClient.Do to satisfy the linter and propagate context. Ref: https://redhat.atlassian.net/browse/EC-1888 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The root command passed context.Background() which is never cancelled, so SIGINT/SIGTERM could not propagate to the server's ctx.Done() select. Use signal.NotifyContext to tie the root context to OS signals. (Change suggested during code review.) Ref: https://redhat.atlassian.net/browse/EC-1883 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The evaluation and report-build error paths were passing raw error text to the client via fmt.Sprintf. Return generic messages instead, with a distinct "evaluation timed out" for deadline exceeded. Full details are still logged server-side. (Change suggested during code review.) Ref: https://redhat.atlassian.net/browse/EC-1887 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
I'm ignoring the two CodeRabbit nitpicks about the license check change. Made changes for a couple of fullsend's fresh nitpicks. |
53dcde7 to
fb2c2f7
Compare
|
🤖 Finished Review · ✅ Success · Started 5:21 PM UTC · Completed 5:33 PM UTC |
This adds an
ec validate input --servercommand that starts up a web service that responds on/v1/validate/inputwith the results the same as if you ranec validate input --output jsonwith the request body as the input fileRef: https://redhat.atlassian.net/browse/EC-1882